﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Globalization;

namespace System.Windows.Art
{
    public struct RgbColor : IColor
    {
        private Color value;

        private RgbColor(Color value)
        {
            this.value = value;
        }

        public static RgbColor FromScRgb(Double scAlpha, Double scRed, Double scGreen, Double scBlue)
        {
            return new RgbColor(Color.FromScRgb((Single)scAlpha, (Single)scRed, (Single)scGreen, (Single)scBlue));
        }

        public Color ToColor() { return this.value; }
        public ColorSpaceBase Space { get { return ColorSpaces.Rgb; } }

        public Double GetValue(ColorChannel channel)
        {
            var space = ColorSpaces.Rgb;
            if (channel == space.Alpha) return this.ScAlpha;
            else if (channel == space.Red) return this.ScRed;
            else if (channel == space.Green) return this.ScGreen;
            else if (channel == space.Blue) return this.ScBlue;
            else throw new InvalidOperationException();
        }

        public void SetValue(ColorChannel channel, Double value)
        {
            var space = ColorSpaces.Rgb;
            if (channel == space.Alpha) this.ScAlpha = value;
            else if (channel == space.Red) this.ScRed = value;
            else if (channel == space.Green) this.ScGreen = value;
            else if (channel == space.Blue) this.ScBlue = value;
            else throw new InvalidOperationException();
        }

        public Double GetClassicValue(ColorChannel channel)
        {
            var space = ColorSpaces.Rgb;
            if (channel == space.Alpha) return this.Alpha;
            else if (channel == space.Red) return this.Red;
            else if (channel == space.Green) return this.Green;
            else if (channel == space.Blue) return this.Blue;
            else throw new InvalidOperationException();
        }

        public void SetClassicValue(ColorChannel channel, Double value)
        {
            var space = ColorSpaces.Rgb;
            if (channel == space.Alpha) this.Alpha = (Byte)value;
            else if (channel == space.Red) this.Red = (Byte)value;
            else if (channel == space.Green) this.Green = (Byte)value;
            else if (channel == space.Blue) this.Blue = (Byte)value;
            else throw new InvalidOperationException();
        }

        public static implicit operator Color(RgbColor value) { return value.value; }
        public static implicit operator RgbColor(Color value) { return new RgbColor(value); }

        public Byte Alpha
        {
            get { return this.value.A; }
            set { this.value.A = value; }
        }

        /// <summary>
        /// Classic Alpha scaled to [0; 1].
        /// <remarks>Linear, unbounded.</remarks>
        /// </summary>
        public Double ScAlpha
        {
            get { return this.value.ScA; }
            set { this.value.ScA = (Single)value; }
        }

        public Byte Red
        {
            get { return this.value.R; }
            set { this.value.R = value; }
        }

        /// <summary>
        /// Classic Red scaled to [0; 1].
        /// <remarks>Non-linear, unbounded.</remarks>
        /// </summary>
        public Double ScRed
        {
            get { return this.value.ScR; }
            set { this.value.ScR = (Single)value; }
        }

        public Byte Green
        {
            get { return this.value.G; }
            set { this.value.G = value; }
        }

        /// <summary>
        /// Classic Green scaled to [0; 1].
        /// <remarks>Non-linear, unbounded.</remarks>
        /// </summary>
        public Double ScGreen
        {
            get { return this.value.ScG; }
            set { this.value.ScG = (Single)value; }
        }

        public Byte Blue
        {
            get { return this.value.B; }
            set { this.value.B = value; }
        }

        /// <summary>
        /// Classic Blue scaled to [0; 1].
        /// <remarks>Non-linear, unbounded.</remarks>
        /// </summary>
        public Double ScBlue
        {
            get { return this.value.ScB; }
            set { this.value.ScB = (Single)value; }
        }

        public override String ToString()
        {
            return this.ToString("g", CultureInfo.CurrentCulture);
        }

        public String ToString(String format)
        {
            return this.ToString(format, CultureInfo.CurrentCulture);
        }

        public String ToString(String format, IFormatProvider provider)
        {
            var builder = new StringBuilder();

            builder.Append(this.Space.ToString()).Append('#');
            builder.Append(this.ScAlpha.ToString(format, provider)).Append("; ");
            builder.Append(this.ScRed.ToString(format, provider)).Append("; ");
            builder.Append(this.ScGreen.ToString(format, provider)).Append("; ");
            builder.Append(this.ScBlue.ToString(format, provider));

            return builder.ToString();
        }

        public Object Clone()
        {
            return this.MemberwiseClone();
        }
    }
}
